#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include "udp_client.hpp"

namespace gimabl {

UdpClient::UdpClient(ThreadMode mode)
:m_mode(mode),
m_sockfd(-1),
m_isConnect(false),
m_port(-1),
m_stop(false),
m_receiveHandle(nullptr),
m_timeoutMs(0)
{

}

UdpClient::~UdpClient()
{

}

int32_t UdpClient::udpInit(std::string serverIp,int32_t serverPort,int32_t port)
{
    int32_t ret=-1;
    sockaddr_in local_addr;

    if(serverIp.empty()|| serverPort==0)
    {
        std::cerr << "intput param is error" << std::endl;
        return ret;
    }
    if(m_sockfd>0)
    {
        std::cerr << "udp socket have connect!!" << strerror(errno)<< std::endl;
        return ret;
    }

    // create local socket
    m_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (m_sockfd < 0) {
        std::cerr << "创建套接字失败: " << strerror(errno) << std::endl;
        return ret;
    }

    m_port=port;

    // bind local addr
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = INADDR_ANY;  // 绑定到所有可用接口
    // local_addr.sin_addr.s_addr = inet_addr("192.168.59.128");
    local_addr.sin_port = htons(m_port);

    if (bind(m_sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
        std::cerr << "绑定端口失败: " << strerror(errno) << std::endl;
        close(m_sockfd);
        m_sockfd=-1;
        return ret;
    }

    // bind server addr
    m_serverLen=sizeof(m_serverAddr);
    memset(&m_serverAddr, 0, sizeof(m_serverAddr));
    m_serverAddr.sin_family = AF_INET;
    m_serverAddr.sin_port = htons(serverPort);

    if (inet_pton(AF_INET, serverIp.c_str(), &m_serverAddr.sin_addr) <= 0) {
        std::cerr << "无效的IP地址" << std::endl;
        close(m_sockfd);
        m_sockfd=-1;
        return ret;
    }
    m_isConnect=true;
 
    if(m_mode==ThreadMode::mutiple)
    {
        m_sendThread=std::thread(&UdpClient::mutilSendMessages,this);
    }
    return 0;
}

void UdpClient::udpClose()
{
    m_stop=true;
    m_isConnect=false;
    if(m_sockfd>0)
    {
        close(m_sockfd);
        m_sockfd=-1;
    }
    if (m_receiverThread.joinable()) {
        m_receiverThread.join();  
    }

    if(m_mode==ThreadMode::mutiple)
    {
        send_cv.notify_one();
        if(m_sendThread.joinable())
        {
            m_sendThread.join();
        }
        while (!m_sendQueue.empty()) {
            m_sendQueue.pop(); // 逐个弹出，触发字符串析构
        }
    }
}

bool UdpClient::isStop()
{
    return m_stop;
}

int32_t UdpClient::udpSend(const void *buf,size_t size)
{
    int32_t ret=-1;
    ssize_t bytes_sent;
    bytes_sent = sendto(m_sockfd, buf, size, 0,
                        (struct sockaddr *)&m_serverAddr, m_serverLen);
    if (bytes_sent < 0) {
        std::cerr << "发送数据失败: " << strerror(errno) << std::endl;
        return ret;
    } 
    ret=bytes_sent;
    return ret;     
}

void UdpClient::mutilSendMessages()
{

    while(!m_stop)
    {
        std::unique_lock<std::mutex> lock(m_sendMutex);
        send_cv.wait_for(lock,std::chrono::milliseconds(Mutil_Wait_Time),[this](){return !m_sendQueue.empty()||m_stop;});
        if(m_stop)
            break;
        if(m_sendQueue.size()>0)
        {
            std::string msg=m_sendQueue.front();
            m_sendQueue.pop();
            lock.unlock();          
            if(msg.size()>0)
            {
                udpSend(msg.c_str(),msg.size());
            }
        }
    }

     std::cout << "mutilSendMessages handle is exit!" << std::endl;
}

int32_t UdpClient::udpWrite(const void *buf,size_t size)
{
    int32_t ret=-1;
    if(!m_isConnect || m_sockfd<0)
    {
        std::cerr << "not connect server services" << std::endl;
        return ret;
    }

    if(buf==nullptr || size==0)
    {
        std::cerr << "intput udp_write param error" << std::endl;
        return ret;
    }

    if(m_mode==ThreadMode::mutiple)
    {
        if(m_sendQueue.size()>MAX_QUEUE_SIZE){
            std::cerr << "send queue is full" << std::endl;
            return ret;
        }
        std::unique_lock<std::mutex> lock(m_sendMutex);
        m_sendQueue.push(std::string((char*)buf,size));
        lock.unlock();
        send_cv.notify_one();
        ret=0;
    }else
    {
        ret=udpSend(buf,size);
    }
    return ret ;
}

void UdpClient::receiveMssages()
{
    
    uint8_t buffer[READ_BUFFER_SIZE];
    std::string message;

    int max_fd = m_sockfd; // 最大文件描述符
    fd_set read_fds;
    int sect_timeout = m_timeoutMs/1000;
    int usec_timeout = (m_timeoutMs % 1000) * 1000;

    while (!m_stop) 
    {
        // 每次调用select前都需要重新初始化集合
        FD_ZERO(&read_fds);
        FD_SET(m_sockfd, &read_fds);       // 监听套接字
        FD_SET(STDIN_FILENO, &read_fds); // 监听标准输入

        timeval timeout;
        timeout.tv_sec = sect_timeout;
        timeout.tv_usec = usec_timeout;

        // 等待事件发生
        int activity = select(max_fd + 1, &read_fds, nullptr, nullptr, &timeout);
        
        if (activity < 0) {
            if (errno != EINTR) { // 忽略中断信号
                std::cerr << "select失败: " << strerror(errno) << std::endl;
                break;
            }
        }
        // 超时不做处理，继续循环
        else if (activity == 0) {
            continue;
        }

        // 处理套接字接收事件
        if (FD_ISSET(m_sockfd, &read_fds)) {
            memset(buffer, 0, READ_BUFFER_SIZE);
            ssize_t bytes_received = recvfrom(m_sockfd, buffer, READ_BUFFER_SIZE - 1, 0,
                                             (struct sockaddr *)&m_serverAddr, &m_serverLen);
            
            if (bytes_received < 0) {
                std::cerr << "接收数据失败: " << strerror(errno) << std::endl;
            } else {
                if(m_receiveHandle)
                {
                    m_receiveHandle(buffer,bytes_received);
                }else
                {
                    std::cout << "m_receiveHandle is nullptr" << std::endl;
                }
            }
        }

    }

    std::cout << "receive_messages handle is exit!" << std::endl;

}

void UdpClient::udpRead(udpRecHandle handle,int32_t timeoutMs)
{
    if(m_sockfd<0 || !m_isConnect)
    {
        std::cerr << "start udp_read failed!" << std::endl;
        return ;
    }
    if(m_receiveHandle==nullptr)
    {
        m_receiveHandle = handle;
    }
    m_receiverThread = std::thread(&UdpClient::receiveMssages, this);
    m_timeoutMs=timeoutMs;
}

}

